/*
 * Copyright 2020 Echedey López Romero.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Equipo del entorno de trabajo con sus características y su software.
 *
 * @author Echedey López Romero
 */
public abstract class Equipo implements Comparable<Equipo> {

	protected List<Software> softwares;
	private String marca;
	private String modelo;
	private String procesador;
	private int memoria;
	private float almacenamiento;

	/**
	 * Se inicializan las especificaciones del equipo por los parámetros
	 * introducidos a excepción de la colección de software que simplemente se
	 * define.
	 *
	 * @param marca empresa o logo
	 * @param modelo nombre publicitario
	 * @param procesador características
	 * @param memoria cantidad de memoria RAM en megabytes
	 * @param almacenamiento capacidad de almacenamiento en gigabytes
	 */
	public Equipo(String marca, String modelo, String procesador, int memoria, float almacenamiento) {
		softwares = new ArrayList<>();
		if (marca == null) {
			throw new NullPointerException("No se ha introducido la marca.");
		} else if (modelo == null) {
			throw new NullPointerException("No se ha introducido el modelo.");
		} else {
			this.marca = marca;
			this.modelo = modelo;
			setProcesador(procesador);
			setMemoria(memoria);
			setAlmacenamiento(almacenamiento);
		}
	}

	/**
	 * Getter para la lista de software.
	 * 
	 * @return lista de software
	 */
	public List<Software> getSoftwares() {
		return softwares;
	}
	
	/**
	 * Getter para la marca.
	 *
	 * @return marca
	 */
	public String getMarca() {
		return marca;
	}

	/**
	 * Getter para el modelo.
	 *
	 * @return modelo
	 */
	public String getModelo() {
		return modelo;
	}

	/**
	 * Getter para el procesador.
	 *
	 * @return características
	 */
	public String getProcesador() {
		return procesador;
	}

	/**
	 * Getter para la memoria RAM.
	 *
	 * @return cantidad de memoria RAM en megabytes
	 */
	public int getMemoria() {
		return memoria;
	}

	/**
	 * Getter para el almacenamiento.
	 *
	 * @return capacidad de almacenamiento en gigabytes
	 */
	public float getAlmacenamiento() {
		return almacenamiento;
	}

	/**
	 * Setter para el procesador.
	 *
	 * @param procesador características
	 */
	public void setProcesador(String procesador) {
		if (procesador == null) {
			throw new NullPointerException("No se ha introducido el procesador.");
		} else {
			this.procesador = procesador;
		}
	}

	/**
	 * Setter para la memoria RAM.
	 *
	 * @param memoria cantidad de memoria RAM en megabytes
	 */
	public void setMemoria(int memoria) {
		if (memoria <= 1024) {
			throw new IllegalArgumentException("Se ha introducido una cantidad de memoria RAM muy baja.");
		} else {
			this.memoria = memoria;
		}
	}

	/**
	 * Setter para el almacenamiento.
	 *
	 * @param almacenamiento capacidad de almacenamiento en gigabytes
	 */
	public void setAlmacenamiento(float almacenamiento) {
		if (almacenamiento < 40.0) {
			throw new IllegalArgumentException("Se ha introducido una capacidad de almacenamiento muy baja.");
		} else {
			this.almacenamiento = almacenamiento;
		}
	}

	/**
	 * Instala un software añadiendolo a la lista de software. Se define en las
	 * subclases y está pensado para usar cuantoSoftware.
	 *
	 * @param software a instalar
	 * @return true si se pudo efectuar y false si no
	 */
	public abstract boolean instalar(Software software);

	/**
	 * Desinstala un software eliminándolo de la lista de software.Se define en
	 * las subclases y está pensado para usar cuantoSoftware.
	 *
	 * @param software a desinstalar
	 * @return true si se pudo efectuar y false si no
	 */
	public abstract boolean desinstalar(Software software);

	/**
	 * Actualiza o renueva la licencia, si tiene, de un software.
	 *
	 * @param software a mantener
	 * @return true si se pudo efectuar y false si no
	 */
	public boolean mantener(Software software) {
		int posicion = softwares.indexOf(software);

		if (posicion != -1) {
			if (software.getLicencia() != null) {
				return software.actualizarVersion() && software.renovarLicencia();
			} else {
				return software.actualizarVersion();
			}
		} else {
			throw new IllegalArgumentException("El software no está instalado");
		}
	}

	/**
	 * Indica cuanto software de cada tipo hay en la lista de sofware.
	 *
	 * @return vector con la cantidad de software de cada tipo
	 */
	protected int[] cuantoSoftware() {
		int[] cantidadsoftware = new int[2];

		for (Software software : softwares) {
			if (software.getTipo() == TipoSoftware.SISTEMAOPERATIVO) {
				cantidadsoftware[0]++;
			} else {
				cantidadsoftware[1]++;
			}
		}

		return cantidadsoftware;
	}

	/**
	 * Ordena la lista de software.
	 */
	public void ordenar() {
		Collections.sort(softwares);
	}

	/**
	 * Genera un resumen de las especificaciones del equipo y su software bien
	 * estructurado.
	 *
	 * @return resumen del equipo y su software
	 */
	@Override
	public String toString() {
		String especificaciones = "Marca: " + getMarca() + "\n"
				+ "Modelo: " + getModelo() + "\n"
				+ "Procesador: " + getProcesador() + "\n"
				+ "Memoria RAM: " + getMemoria() + "\n"
				+ "Almacenamiento: " + getAlmacenamiento() + "\n\n"
				+ "Softwares: \n\n";

		for (Software software : softwares) {
			especificaciones += software.toString();
		}

		return especificaciones;
	}

	/**
	 * Compara equipos en base a la marca y el modelo mediante el
	 * compareToIgnoreCase para cadenas.
	 *
	 * @param otroEquipo equipo a comparar
	 * @return comparación de cadenas
	 */
	@Override
	public int compareTo(Equipo otroEquipo) {
		String infoEquipo = getMarca()
				+ getModelo();
		String infoOtroEquipo = otroEquipo.getMarca()
				+ otroEquipo.getModelo();

		return infoEquipo.compareToIgnoreCase(infoOtroEquipo);
	}

}
